﻿using System;

namespace LAPI.Core
{

    public static class MathsExtension
    {
        /// <summary>
        /// Compara dos floats, con un margen aceptable.
        /// </summary>
        /// <param name="left">float 1</param>
        /// <param name="right">float 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si son iguales, false en cualquier otro caso</return>
        public static bool FloatEqualTo(float left, float right, float epsilon)
        {
            return Math.Abs(left - right) <= epsilon;
        }

        /// <summary>
        /// Compara dos floats, con un margen aceptable.
        /// </summary>
        /// <param name="left">float 1</param>
        /// <param name="right">float 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si el izquierdo es mayor que el derecho, false en cualquier otro caso</return>
        public static bool FloatGreaterThan(float left, float right, float epsilon)
        {
            // delegate
            return FloatGreaterThan(left, right, epsilon, false);
        }

        /// <summary>
        /// Compara dos floats, con un margen aceptable.
        /// </summary>
        /// <param name="left">float 1</param>
        /// <param name="right">float 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si el izquierdo es mayor o igual que el derecho, false en cualquier otro caso</return>
        public static bool FloatGreaterThanOrEqualTo(float left, float right, float epsilon)
        {
            // delegate
            return FloatGreaterThan(left, right, epsilon, true);
        }

        private static bool FloatGreaterThan(float left, float right, float epsilon, bool orEqualTo)
        {
            if (FloatEqualTo(left, right, epsilon))  // within epsilon, so considered equal
            {
                return orEqualTo;
            }
            return left > right;
        }

        /// <summary>
        /// Compara dos floats, con un margen aceptable.
        /// </summary>
        /// <param name="left">float 1</param>
        /// <param name="right">float 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si el izquierdo es menor que el derecho, false en cualquier otro caso</return>
        public static bool FloatLessThan(float left, float right, float epsilon)
        {
            // delegate
            return FloatLessThan(left, right, epsilon, false);
        }

        /// <summary>
        /// Compara dos floats, con un margen aceptable.
        /// </summary>
        /// <param name="left">float 1</param>
        /// <param name="right">float 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si el izquierdo es menor o igual que el derecho, false en cualquier otro caso</return>
        public static bool FloatLessThanOrEqualTo(float left, float right, float epsilon)
        {
            // delegate
            return FloatLessThan(left, right, epsilon, true);
        }

        private static bool FloatLessThan(float left, float right, float epsilon, bool orEqualTo)
        {
            if (FloatEqualTo(left, right, epsilon))
            {
                // within epsilon, so considered equal
                return orEqualTo;
            }
            return left < right;
        }

        /// <summary>
        /// Compara dos Doubles, con un margen aceptable.
        /// </summary>
        /// <param name="left">double 1</param>
        /// <param name="right">double 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si son iguales, false en cualquier otro caso</return>
        public static bool DoubleEqualTo(double left, double right, double epsilon)
        {
            return Math.Abs(left - right) <= epsilon;
        }

        /// <summary>
        /// Compara dos Doubles, con un margen aceptable.
        /// </summary>
        /// <param name="left">double 1</param>
        /// <param name="right">double 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si el de la izquierda es superior al de la derecha, false en cualquier otro caso</return>
        public static bool DoubleGreaterThan(double left, double right, double epsilon)
        {
            // delegate
            return DoubleGreaterThan(left, right, epsilon, false);
        }

        /// <summary>
        /// Compara dos Doubles, con un margen aceptable.
        /// </summary>
        /// <param name="left">double 1</param>
        /// <param name="right">double 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si el de la izquierda es superior o igual al de la derecha, false en cualquier otro caso</return>
        public static bool DoubleGreaterThanOrEqualTo(double left, double right, double epsilon)
        {
            // delegate
            return DoubleGreaterThan(left, right, epsilon, true);
        }

        private static bool DoubleGreaterThan(double left, double right, double epsilon, bool orEqualTo)
        {
            if (DoubleEqualTo(left, right, epsilon))// within epsilon, so considered equal
            {
                return orEqualTo;
            }
            return left > right;
        }

        /// <summary>
        /// Compara dos Doubles, con un margen aceptable.
        /// </summary>
        /// <param name="left">double 1</param>
        /// <param name="right">double 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si el de la izquierda es inferior al de la derecha, false en cualquier otro caso</return>
        public static bool DoubleLessThan(double left, double right, double epsilon)
        {
            // delegate
            return DoubleLessThan(left, right, epsilon, false);
        }

        /// <summary>
        /// Compara dos Doubles, con un margen aceptable.
        /// </summary>
        /// <param name="left">double 1</param>
        /// <param name="right">double 2</param>
        /// <param name="epsilon">margen aceptable</param>
        /// <returns>true si el de la izquierda es inferior o igual al de la derecha, false en cualquier otro caso</return>
        public static bool DoubleLessThanOrEqualTo(double left, double right, double epsilon)
        {
            // delegate
            return DoubleLessThan(left, right, epsilon, true);
        }

        private static bool DoubleLessThan(double left, double right, double epsilon, bool orEqualTo)
        {
            if (DoubleEqualTo(left, right, epsilon)) // within epsilon, so considered equal
            {
                return orEqualTo;
            }
            return left < right;
        }
    }
}
